

namespace GMlib
{
	template <typename T>
	inline
	BSpline<T>::BSpline(T size)
	{
		_size = size;
		this->_dm = GMlib::GM_DERIVATION_EXPLICIT;
	}

	template <typename T>
	inline 
	BSpline<T>::BSpline( DVector<Vector<T, 3>> pts, int deg )
	{
		this->_dm = GM_DERIVATION_EXPLICIT;

		_deg = deg;

		//_bernMat.setDim( pts.getDim()+1, pts.getDim()+1 );
		// _pts.setDim( pts.getDim() );
		_pts = pts;
		//for( int i = 0; i < pts.getDim(); i++ )
		//{
		//	_pts[i][0] = pts[i][0];
		//	_pts[i][1] = pts[i][1];
		//	_pts[i][2] = pts[i][2];
		//}
		_size = 1;

		 int order = _deg + 1;
	 
		 _knots.setDim( _pts.getDim() + order );
		 int step_knots = _knots.getDim() - ( order * 2 );
	 
		 T knot_value = T(0);
		 int i = 0;
	 
		 // Set the start knots
		 for( ; i < order; i++ )
		   _knots[i] = knot_value;
	 
		 // Set the "step"-knots
		 for( int j = 0; j < step_knots; j++ )
		   _knots[i++] = ++knot_value;
	 
		 // Set the end knots
		 knot_value++;
		 for( ; i < _knots.getDim(); i++ )
			 _knots[i] = knot_value;
	}

	template <typename T>
	inline
	BSpline<T>::BSpline( const BSpline<T>& copy ) : GMlib::PCurve<T>( copy ) {}

	template <typename T>
	inline
	BSpline<T>::~BSpline() {}

	template <typename T>
	inline
	T BSpline<T>::calcW(T t, int idx, int d)
	{
		T w = (t - _knots[idx]) / (_knots[idx+d] - _knots[idx]);

		return w;
	}

	template <typename T>
	inline
	void BSpline<T>::calcBern(int d, T t, T delta, int idx)
	{
		DVector<T> w;
		d = _deg;

		_bernMat.setDim(d+1,d+1);

		_bernMat[d-1][0] = 1-calcW(t, idx, 1);
		_bernMat[d-1][1] = calcW(t, idx, 1);
		for(int i=d-2, d_c = 2; i>=0; i--, d_c++)
		{
			w.setDim(d_c);

			for (int j = d_c; j > 0; j--)
				w[j-1] = calcW(t, idx - (d_c - j), d_c);

			_bernMat[i][0] = (1-w[0]) * _bernMat[i+1][0];
			for(int j=1; j<d-i; j++)
			{
					_bernMat[i][j] = w[j-1]*_bernMat[i+1][j-1] + (1-w[j])*_bernMat[i+1][j];
			}
			_bernMat[i][d-i] = w[d_c-1]*_bernMat[i+1][d-i-1];
		}

	}


	template <typename T> 
	inline
	void BSpline<T>::eval( T t, int d, bool l ) // calc _p ?
	{

		int idx = _deg;
		while ( true )
		{
			if ( t > _knots[idx+1] )
				idx++;
			else 
				break;
		}

		calcBern(_deg, t, 1.0f, idx);
		
		DVector< Vector<float,3> > c;
		c.setDim( _deg + 1 );
		for( int j = 0; j <= _deg; j++ )
			c[j] = _pts[idx-(_deg-j)];

		this->_p = _bernMat * c;


	}

	template <typename T>
	inline
	T BSpline<T>::getEndP()  
	{
		//std::cout << _knots[_pts.getDim() + _deg] << "\n";
		return _knots[_pts.getDim() + _deg];
	}

	template <typename T>
	inline
	T BSpline<T>::getStartP() 
	{
		return T(0.0);
	}

	template <typename T>
	inline
	bool BSpline<T>::isClosed() const
	{
		return false;
	}

	template <typename T>
	inline
	std::string BSpline<T>::getIdentity() const 
	{
		return "BSpline";
	}

}

